home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Overview / Signals / UFailure.a < prev    next >
Encoding:
Text File  |  1994-11-18  |  11.8 KB  |  393 lines  |  [TEXT/MPS ]

  1. ;
  2. ;    Apple Macintosh Developer Technical Support
  3. ;
  4. ;    Exception handling for MPW Pascal, MacApp and MPW C
  5. ;
  6. ;    UFailure (aka Signals) - “Exceptional code, with a few exceptions.”
  7. ;
  8. ;    UFailure.a    -    Assembly Source
  9. ;
  10. ;    Copyright © 1985-1988 Apple Computer, Inc.
  11. ;    All rights reserved.
  12. ;
  13. ;    Versions:    1.00                11/88
  14. ;                1.01                06/92
  15. ;
  16. ;    Components:    CTestSignal.c        November 1, 1988
  17. ;                CTestSignal.make    November 1, 1988
  18. ;                PTestSignal.p        November 1, 1988
  19. ;                PTestSignal.make    November 1, 1988
  20. ;                UFailure.p            November 1, 1988
  21. ;                UFailure.h            November 1, 1988
  22. ;                UFailure.incl.p        November 1, 1988
  23. ;                UFailure.a            November 1, 1988
  24. ;
  25. ;    UFailure (or Signals) is a set of exception handling routines suitable for
  26. ;    use with MacApp, MPW C, and MPW Pascal. It is a jazzed-up version of the MacApp
  27. ;    UFailure unit. There is a set of C interfaces to it as well.
  28. ;
  29.  
  30.             PRINT    OFF
  31.             INCLUDE    'Traps.a'
  32.             PRINT    ON
  33.             
  34.             STRING    ASIS
  35.  
  36. ;=============================================================================================
  37.             GblA    &UsingMacApp
  38.     If        &TYPE('&Debugging') = 'UNDEFINED' Then
  39.             GblA    &Debugging
  40. &UsingMacApp    SetA    0            ; we assume we’re MacAppless if &Debugging isn’t defined 
  41.         If        &TYPE('&Debug') = 'UNDEFINED' Then
  42. &Debugging    SetA    0            ; default to debugging off
  43.         Else
  44. &Debugging    SetA    &Debug        ; use the makefile definition of &Debug
  45.         EndIf
  46.     Else    
  47. &UsingMacApp    SetA    1            ; we assume we have MA if &Debugging is defined 
  48.     EndIf
  49. ;=============================================================================================
  50.     If        &TYPE('Head') = 'UNDEFINED' Then
  51.         Macro    
  52.         Head
  53.                 GblA    &Debugging
  54.             If  &Debugging Then
  55.                 Link    A6,#0        ; These two instructions form a slow no-op
  56.                 Move.L    (SP)+,A6
  57.             EndIf
  58.         EndM
  59.     EndIf
  60. ;=============================================================================================
  61.     If        &TYPE('Tail') = 'UNDEFINED' Then
  62.         Macro    
  63.         Tail
  64.                 GblA    &Debugging
  65.             If  &Debugging Then
  66.                 Unlk    A6
  67.                 Rts
  68.                 DC.B    &Ord(&SubStr(&Syslst[1],2,1)) + $80
  69.                 DC.B    '&SubStr(&Syslst[1],3,7)'
  70.             EndIf
  71.         EndM
  72.     EndIf
  73. ;=============================================================================================
  74.         
  75. ; the following constant sets the limit on the depth of nested CatchSignals
  76. SigBlockSize EQU    8                            ;number of elements in block
  77.  
  78. CatchSigErr    EQU        200                            ;"insufficient heap" message
  79. SigElSize    EQU        72                            ;byte size of FailInfo record
  80. FrameRet    EQU        4                            ;return addr. for frame (off A6)
  81. SigBigA6    EQU        $FFFFFFFF                    ;A6 at outer level (for Pascal)
  82. nSavedRegs    EQU     11                            ;number of registers saved in FailInfo record
  83.  
  84. ; offsets into the FailInfo record (see UFailure.p)
  85. SigA6        EQU        36
  86. SigSP        EQU        40
  87. SigCode        EQU        44
  88. SigMessage    EQU        46
  89. SigFailA6    EQU        50
  90. SigFailPC    EQU        54
  91. whatSignals    EQU        66
  92. SigFRet        EQU        68
  93.  
  94.     
  95. ; The global data used by these routines follows. It is in the form of a 
  96. ; RECORD, but, unlike above, no origin is specified, which means that memory 
  97. ; space *will* be allocated.
  98. ; This data is referenced through a WITH statement at the beginning of the 
  99. ; procs that need to get at this data. Since the Assembler knows when it is 
  100. ; referencing data in a data module (since they must be declared before they 
  101. ; are accessed), and since such data can only be accessed based on A5, there 
  102. ; is no need to explicitly specify A5 in any code which references the data 
  103. ; (unless indexing is used).  Thus, in this program we have omitted all A5 
  104. ; references when referencing the data.
  105.  
  106. SigGlobals RECORD        ;no origin means this is a data record
  107.                         ;not a template(as above)
  108. SigEnd        DS.L    1    ;current end of table
  109. SigNow        DS.L    1    ;the current offset
  110. SigPointer    DC.L    0    ;the handle := 0 initially
  111.             ENDR    
  112.  
  113.  
  114.         If  &UsingMacApp Then
  115.             Seg     'MAInit'
  116.         EndIf
  117. InitSignals    PROC    EXPORT                        ;PROCEDURE InitSignals;
  118.             EXPORT    InitUFailure
  119.             IMPORT    gTopHandler:Data
  120.             IMPORT    gInitHandler:Data
  121.         If  &UsingMacApp And &Debugging Then
  122.             IMPORT    gAskAboutAlloc:Data
  123.             IMPORT    gAskFailure:Data
  124.         EndIf
  125.             WITH    SigGlobals
  126. ;the above statement makes the template SigElement and the global data 
  127. ;record SigGlobals available to this procedure
  128.  
  129.              Head
  130.             MOVE.L    #SigBigA6,A6                ;make A6 valid for Signal
  131. InitUFailure                                    ;PROCEDURE InitUFailure;
  132.             CLR.L    gTopHandler(A5)                ;nothing in the list
  133.             CLR.L    gInitHandler(A5)            ;MA has another list during initialization
  134.         If  &UsingMacApp And &Debugging Then
  135.             CLR.B    gAskAboutAlloc(A5)            ;set the MA debugging guys to FALSE
  136.             CLR.B    gAskFailure(A5)
  137.         EndIf
  138.  
  139.             MOVE.L    #SigBlockSize*SigElSize,D0
  140.             _NewPtr                                ;try to get a table
  141.             BNE.S    forgetit                    ;we couldn't get that!?
  142.             
  143.             MOVE.L    A0,SigPointer                ;save it
  144.             MOVE.L    #-SigElSize,SigNow            ;point "now" before start
  145.             MOVE.L    #SigBlockSize*SigElSize,SigEnd ;save the end
  146. forgetit    RTS
  147.         
  148.             Tail    'INITUFAI'
  149.             ENDP
  150.  
  151.  
  152.         If  &UsingMacApp Then
  153.             Seg     'MAMain'
  154.         EndIf
  155. CatchCFailures PROC    EXPORT                        ;pascal void CatchCFailures(FailInfo &fi, HandlerFuncPtr handler);
  156.             IMPORT    FailCEntry
  157.             
  158.             Head
  159.             MOVE.L    (A7)+,D2                    ;save return address
  160.             MOVEQ    #0,D1                        ;CatchCFailures used  (no A6 link, uses handler proc.)
  161.             BRA.S    FailCEntry                    ;finish from CatchFailures
  162.             Tail    'CATCHCFA'
  163.  
  164. CatchFailures PROC    EXPORT                        ;PROCEDURE CatchFailures(VAR fi: FailInfo;
  165. ;                                                    PROCEDURE Handler(code: INTEGER; message: LONGINT));
  166.             IMPORT    FailuresEntry
  167.             EXPORT    FailCEntry
  168.             WITH    SigGlobals
  169.             
  170.             Head
  171.             MOVE.L    (A7)+,D2                    ;save return address
  172.             ADDQ    #4,A7                        ;discard A6 link
  173.             MOVEQ    #-1,D1                        ;CatchFailures used  (maybe A6 link???, handler proc.)
  174. FailCEntry
  175.             MOVE.L    (A7)+,A1                    ;get handler address
  176.             MOVE.L    (A7)+,A0                    ;FailInfo record address
  177.             BRA.S    FailuresEntry                ;enter CatchSignal with D2, A0, A1 set
  178.             Tail    'CATCHFAI'
  179.  
  180. CatchSignal    PROC    EXPORT                        ;FUNCTION CatchSignal:INTEGER
  181.             IMPORT    SiggyPop2,Signal,SigDeath
  182.             IMPORT    gTopHandler:Data
  183.             EXPORT    FailuresEntry
  184.             WITH    SigGlobals
  185.             
  186.             Head
  187.             MOVE.L    (A7)+,A1                    ;grab return address for “handler” address
  188.             MOVE.L    A1,D2                        ;save return address
  189.             MOVEQ    #1,D1                        ;CatchSignals used; no A6 link needed on stack, no proc.
  190.             CLR.W    (A7)                        ;no error code (before its time)
  191.  
  192.             MOVE.L    SigPointer,D0                ;point to table
  193.             BEQ        SigDeath
  194.             MOVE.L    D0,A0
  195.             MOVE.L    SigNow,D0
  196.             ADD.L    #SigElSize,D0
  197.             MOVE.L    D0,SigNow                    ;save new position
  198.             CMP.L    SigEnd,D0                    ;have we reached the end?
  199.             BNE.S    catchit                        ;no, proceed
  200.             
  201. ;signals, we use 'em ourselves
  202.             MOVE.L    SigNow,SigEnd                ;restore old ending offset
  203.             MOVE.L    #SigElSize,D0
  204.             SUB.L    D0,SigNow                    ;ditto for current position
  205.             MOVE.W    #CatchSigErr,4(A7)            ;we'll signal a "couldn't
  206.                                                 ;  catch" error
  207.             JSR        Signal                        ;never returns of course
  208.                     
  209. catchit        
  210.             ADD.L    D0,A0                        ;point to new entry
  211. FailuresEntry                                    ;A0=pointer to FailInfo block,A1=handler address,
  212.                                                 ; D1=flag showing how we entered, D2=return address
  213.             MOVE.L    A0,D0                        ;save FailInfo record address
  214.  
  215.             MOVE.W    D1,whatSignals(A0)            ;remember what’s catching (-1=CatchFailures,
  216.                                                 ; 0=CatchCFailures, 1=CatchSignal)
  217.             BLE.S    @1                            ;can’t use frame to clean up if they’ll call Success
  218.  
  219.             CMP.L    #SigBigA6,A6                ;are we at the outer level?
  220.             BEQ.S    @1                            ;yes, no frame, no cleanup needed 
  221.             MOVE.L    FrameRet(A6),SigFRet(A0)    ;save old frame return
  222.                                                 ; address
  223.             LEA        SiggyPop,A0
  224.             MOVE.L    A0,FrameRet(A6)                ;set cleanup code address
  225.             MOVE.L    D0,A0                        ;restore FailInfo record address
  226. @1        
  227.             MOVEM.L A2-A7/D3-D7,(A0)            ;save all registers first (note that the saved
  228.                                                 ; stack points to the function result for CatchSignal)
  229.             ADD     #nSavedRegs*4,A0            ;advance pointer by # bytes regs
  230.         
  231.             CLR.W    (A0)+                        ;clear error field
  232.             CLR.L    (A0)+                        ;clear message field
  233.             CLR.L    (A0)+                        ;clear A6 link
  234.             
  235.             TST.W    D1                            ;was CatchFailures used?
  236.             BPL.S    @2                            ;no, CatchCFailures or CatchSignal; skip
  237.             MOVE.L    A6,-4(A0)                    ;save the A6Link
  238. @2
  239.             MOVE.L    A1,(A0)+                    ;save the handler ptr
  240.         
  241.             MOVE.L    gTopHandler(A5),(A0)+        ;Link the FailInfo into the list
  242.             MOVE.L    D0,gTopHandler(A5)
  243.             MOVE.L    D2,(A0)+                    ;remember the caller's PC for MA debugging
  244.  
  245.             MOVE.L    D2,A0                        ;get return address
  246.             JMP        (A0)
  247.             Tail    'CATCHSIG'
  248.  
  249.             ALIGN
  250. SiggyPop
  251.             Head
  252.             MOVE.L    D0,-(A7)                    ;save D0 in case we’re returning from a c function
  253.  
  254.             MOVE.L    SigPointer,A0
  255.             MOVE.L    A0,D0                        ;to set CCR
  256.             BEQ        SigDeath                    ;nil pointer means trouble
  257.             MOVE.L    SigNow,D0                    ;grab table offset to entry
  258.             BMI        SigDeath                    ;if no entries then give up
  259.             ADD.L    D0,A0                        ;point to current element
  260.             
  261.             MOVE.L    SigFRet(A0),-(A7)            ;push proc's real return address
  262.             BSR        SiggyPop2                    ;pop element and call Success to pop handler
  263.             MOVE.L    (A7)+,A1                    ;get proc’s return address
  264.             MOVE.L    (A7)+,D0                    ;get back D0 in case we’re returning from c
  265.             JMP        (A1)
  266.             Tail    'SIGGYPOP'
  267.             
  268.             ENDP
  269.  
  270.  
  271.  
  272.  
  273.         If  &UsingMacApp Then
  274.             Seg     'MAMain'
  275.         EndIf
  276. FreeSignal    PROC    EXPORT                        ;PROCEDURE FreeSignal;
  277.             IMPORT    SigDeath,Success
  278.             IMPORT    gTopHandler:Data
  279.             EXPORT    SiggyPop2
  280.             WITH    SigGlobals
  281.             
  282.             Head
  283.             MOVE.L    gTopHandler(A5),A0            ;point to FailInfo record
  284.             MOVE.L    A0,D0                        ;to set CCR
  285.             BEQ.S    SigDeath
  286.             
  287.             TST.W    whatSignals(A0)                ;was CatchSignal used?
  288.             BLE.S    SiggyPop3                    ;no, call Success and return
  289.             
  290.             MOVE.L    SigNow,D0                    ;grab table offset to entry
  291.             
  292.             MOVE.L    SigA6(A0),A1                ;get A6 at point of CatchSignal
  293.             CMP.L    #SigBigA6,A1                ;is it at the outer level?
  294.             BEQ.S    SiggyPop2                    ;yes, don't jam the address if no frame 
  295.             MOVE.L    SigFRet(A0),FrameRet(A1)    ;"pop" cleanup code
  296. SiggyPop2
  297.             SUB.L    #SigElSize,D0
  298.             MOVE.L    D0,SigNow                    ;"pop" the entry
  299. SiggyPop3
  300.             MOVE.L    A0,-(A7)                    ;push address for Success (FailInfo’s)
  301.             JSR        Success                        ;let MacApp remove FailInfo from list; return
  302.             RTS
  303.             Tail    'FREESIGN'
  304.             
  305.             ENDP
  306.  
  307.         If  &UsingMacApp Then
  308.             Seg     'MAMain'
  309.         EndIf
  310. SignalMessage PROC    EXPORT                        ;PROCEDURE SignalMessage(code: INTEGER; message: LONGINT);
  311.             IMPORT    SignalEntry
  312.             WITH    SigGlobals
  313.  
  314.             Head
  315.             MOVE.L    (A7)+,A1                    ;get return address    
  316.             MOVE.L    (A7)+,D0                    ;get message
  317.             BRA.S    SignalEntry
  318.             Tail    'SIGNALME'
  319.  
  320. Signal        PROC    EXPORT                        ;PROCEDURE Signal(code:INTEGER);
  321.             IMPORT    Failure
  322.             EXPORT    SigDeath,SignalEntry
  323. code        EQU        4
  324.             WITH    SigGlobals
  325.  
  326.             Head
  327.             MOVE.L    (A7)+,A1                    ;get return address    
  328.             CLR.L    D0                            ;message := 0
  329. SignalEntry
  330.             MOVE.W    (A7)+,D1                    ;get code
  331.             BNE.S    @0                            ;process the signal if code is non-zero
  332.             JMP    (A1)                            ;return to caller (code was 0)
  333. @0
  334.             MOVE.W    D1,-(A7)                    ;push code
  335.             MOVE.L    D0,-(A7)                    ;push message
  336.             JSR        Failure                        ;this will pop the handler and call SignalFailure
  337. SigDeath
  338.             _Debugger                            ;wasn’t supposed to come back…
  339.             Tail    'SIGNAL  '
  340.  
  341.             ENDP
  342.  
  343.         If  &UsingMacApp Then
  344.             Seg     'MAMain'
  345.         EndIf
  346. DoFailure    PROC    EXPORT                        ;PROCEDURE DoFailure(VAR fi: FailInfo);
  347.             IMPORT    Failure
  348. fi            EQU        4
  349.             
  350.             Head
  351.             BSR        FreeSignal                    ;pop this guy off (but the record is still valid)
  352.             
  353.             MOVE.L    fi(A7),A0                    ;get FailInfo record
  354.             
  355.             MOVEM.L (A0),A2-A7/D3-D7            ;restore regs (can't use A7 anymore)
  356.             ADD     #nSavedRegs*4,A0            ;advance pointer
  357.         
  358.             MOVE.W    (A0)+,D0                     ;get error
  359.         
  360.             TST.W    whatSignals-nSavedRegs*4-2(A0)    ;was CatchSignal used?
  361.             BGT.S    @2                            ;yes, skip
  362.             
  363.             MOVE.L    (A0)+,D1                     ;get message
  364.             MOVEM.L    D0/D1,-(SP)                    ;save error and message for later use
  365.  
  366.             MOVE.W    D0,-(SP)
  367.             MOVE.L    D1,-(SP)                    ;parameters to failure handler
  368.                 
  369.             MOVE.L    (A0)+,D0                    ;check the A6Link
  370.             BEQ.S    @1                            ;if NIL then don't pass it
  371.             MOVE.L    D0,-(SP)                    ;else do pass it
  372. @1
  373.             MOVE.L    (A0)+,A0                    ;get address of failure handler
  374.         
  375.             JSR     (A0)                        ;call failure handler
  376.             
  377.             MOVEM.L    (SP)+,D0/D1                    ;get error & message back
  378.             MOVE.W    D0,-(SP)
  379.             MOVE.L    D1,-(SP)                    ;parameters to Failure
  380.             JSR        Failure
  381.             _Debugger                            ;not supposed to fail to fail
  382.             
  383. @2
  384.             MOVE.W    D0,(A7)                        ;set CatchSignal function result
  385.             MOVE.L    8(A0),A0                    ;address of the failure handler-skip msg. & A6 link
  386.             JMP        (A0)                        ;go to point of CatchSignal
  387.             Tail    'DOFAILUR'
  388.             
  389.             ENDP
  390.                     
  391.  
  392.             END
  393.